/*
* Copyright (C) Microsoft. All rights reserved.  
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not 
* use this file except in compliance with the License.  You may obtain a copy 
* of the License at http://www.apache.org/licenses/LICENSE-2.0  
* 
* THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
* WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
* MERCHANTABLITY OR NON-INFRINGEMENT. 
*
* See the Apache License, Version 2.0 for specific language governing 
* permissions and limitations under the License.
*
*/
#pragma once

#include <baja/stream/storage_folder_interface.h>
#include <baja/stream/storage_file_interface.h>

namespace baja { namespace storage {

class storage_folder :
    public istorage_folder,
    public std::enable_shared_from_this<istorage_folder>
{
public:
    storage_folder()
    {
    }

    static std::shared_ptr<istorage_folder> create()
    {
        std::shared_ptr<storage_folder> returnValue = std::make_shared<storage_folder>();
        return returnValue;
    }

    static std::shared_ptr<istorage_folder> create(Windows::Storage::StorageFolder^ storageFolder)
    {
        std::shared_ptr<storage_folder> returnValue = std::make_shared<storage_folder>();
        returnValue->_storageFolder = storageFolder;
        return returnValue;
    }

    // istorage_folder
    void initializeAsync(std::function<void(bool)> initializeCompleted)
    {
        if (_storageFolder == nullptr)
        {
            BAJA_THROW(std::runtime_error("object is not initialized"));
        }
        initializePropertiesAsync(initializeCompleted);
    }

    void initializeAsync(std::wstring fullPath, std::function<void(bool)> initializeCompleted)
    {
        std::shared_ptr<storage_folder> p_this = std::static_pointer_cast<storage_folder>(shared_from_this());

        Windows::Foundation::IAsyncOperation<Windows::Storage::StorageFolder^>^ op = Windows::Storage::StorageFolder::GetFolderFromPathAsync(ref new Platform::String(fullPath.c_str()));

        op->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler<Windows::Storage::StorageFolder^>(
                [p_this, initializeCompleted](Windows::Foundation::IAsyncOperation<Windows::Storage::StorageFolder^>^ operation, AsyncStatus status)
                {
                    bool success = true;
                    try
                    {
                        p_this->_storageFolder = operation->GetResults();
                        p_this->initializePropertiesAsync(initializeCompleted);
                    }
                    catch(Platform::Exception^ e)
                    {
                        success = false;
                    }
                    if (p_this->_storageFolder == nullptr)
                    {
                        success = false;
                        initializeCompleted(success);
                    }
                }
            );
    }


    void deleteAsync(std::function<void(bool)> deleteCompleted)
    {
        if (_storageFolder == nullptr)
        {
            BAJA_THROW(std::runtime_error("object is not initialized"));
        }

        Windows::Foundation::IAsyncAction^ ac = _storageFolder->DeleteAsync();
        ac->Completed = ref new Windows::Foundation::AsyncActionCompletedHandler(
                [deleteCompleted](Windows::Foundation::IAsyncAction^ ac, AsyncStatus status)
                {
                    bool success = true;
                    try
                    {
                        ac->GetResults();
                    }
                    catch(Platform::Exception^ e)
                    {
                        success = false;
                    }
                    deleteCompleted(success);
                }
            );
    }

    void getFilesAsync(std::function<void(bool, const std::vector<std::shared_ptr<istorage_file>>&)> getFilesCompleted)
    {
        if (_storageFolder == nullptr)
        {
            BAJA_THROW(std::runtime_error("object is not initialized"));
        }
        std::shared_ptr<storage_folder> p_this = std::static_pointer_cast<storage_folder>(shared_from_this());

        Windows::Foundation::IAsyncOperation<Windows::Foundation::Collections::IVectorView<StorageFile^>^>^ ac =  _storageFolder->GetFilesAsync();
        ac->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler<Windows::Foundation::Collections::IVectorView<Windows::Storage::StorageFile ^> ^>(
            [p_this, getFilesCompleted](Windows::Foundation::IAsyncOperation<Windows::Foundation::Collections::IVectorView<Windows::Storage::StorageFile ^> ^>^ operation, AsyncStatus status) 
            {
                    bool success = true;
                    std::vector<std::shared_ptr<istorage_file>> vecIStorageFiles;
                    try
                    {
                        auto storageFiles = operation->GetResults();
                        
                        auto it = storageFiles->First();
                        while (it->HasCurrent) 
                        {
                            vecIStorageFiles.push_back(storage_file::create(it->Current));
                            it->MoveNext();
                        }
                    }
                    catch(Platform::Exception^ e)
                    {
                        success = false;
                    }
                    getFilesCompleted(success, vecIStorageFiles);
            }
        );

    }
private:
    void initializePropertiesAsync(std::function<void(bool)> initializeCompleted)
    {
        std::shared_ptr<storage_folder> p_this = std::static_pointer_cast<storage_folder>(shared_from_this());

        Windows::Foundation::IAsyncOperation<Windows::Storage::FileProperties::BasicProperties^>^ op =  p_this->_storageFolder->GetBasicPropertiesAsync();
        op->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler<Windows::Storage::FileProperties::BasicProperties^>(
                [p_this, initializeCompleted](Windows::Foundation::IAsyncOperation<Windows::Storage::FileProperties::BasicProperties^>^ operation, AsyncStatus status)
                {
                    bool success = true;
                    try
                    {
                        p_this->_storageFileProperties = operation->GetResults();
                    }
                    catch(Platform::Exception^ e)
                    {
                        success = false;
                    }
                    initializeCompleted(success);
                }
            );
    }

    Windows::Storage::StorageFolder^ _storageFolder;
    Windows::Storage::FileProperties::BasicProperties^ _storageFileProperties;
};

inline std::shared_ptr<istorage_folder> createStorageFolder()
{
    return storage_folder::create();
}

inline std::shared_ptr<istorage_folder> createStorageFolder(Windows::Storage::StorageFolder^ storageFolder)
{
    return storage_folder::create(storageFolder);
}

}}// baja::storage
